package com.xxl.job.admin.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.service.PluginService;
import com.xxl.job.admin.utils.FileUtils;
import com.xxl.job.admin.utils.ValidatorUtils;
import com.xxl.job.admin.utils.ZipUtils;
import com.xxl.job.core.commons.exception.DataxException;
import com.xxl.job.core.commons.response.ReturnCode;
import com.xxl.job.core.commons.response.ReturnT;
import com.xxl.job.core.commons.vo.plugin.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Paths;
import java.util.HashMap;

/**
 * @author xuyue
 * @date 2021-4-20 10:53
 * Datax解析器管理
 */
@Api(tags = "Datax解析器管理")
@RestController
@RequestMapping("/plugin")
public class PluginController {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private PluginService pluginService;

    @Autowired
    private XxlJobGroupDao xxlJobGroupDao;
    private String[] urls;

    @PostMapping("add")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "上传文件", dataType = "file", required = true),
            @ApiImplicitParam(name = "name", value = "解析器名称", dataType = "string", required = true),
            @ApiImplicitParam(name = "type", value = "type", dataType = "string", required = true, allowableValues = "reader,writer")})
    @ApiOperation(value = "添加解析器")
    public ReturnT add(
            @RequestParam(name = "file") MultipartFile file,
            @RequestParam("name") String name,
            @RequestParam("type") String type) {
        PluginAddVo pluginAddVo = new PluginAddVo();
        pluginAddVo.setFile(file);
        pluginAddVo.setName(name);
        pluginAddVo.setType(type);

        pluginService.checkFile(file);
        ValidatorUtils.validateEntity(pluginAddVo);
        String uuid = pluginService.add(pluginAddVo);
        return ReturnT.ok().put(uuid);
    }

    @PostMapping("update")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uuid", value = "UUID", dataType = "string", required = true),
            @ApiImplicitParam(name = "file", value = "上传文件", dataType = "file"),
            @ApiImplicitParam(name = "name", value = "解析器名称", dataType = "string", required = true),
            @ApiImplicitParam(name = "type", value = "type", dataType = "string", required = true, allowableValues = "reader,writer")})
    @ApiOperation(value = "更新解析器")
    public ReturnT update(
            @RequestParam("uuid") String uuid,
            @RequestParam(name = "file", required = false) MultipartFile file,
            @RequestParam("name") String name,
            @RequestParam("type") String type) {
        PluginUpdateVo pluginUpdateVo = new PluginUpdateVo();
        pluginUpdateVo.setUuid(uuid);
        //pluginUpdateVo.setFile(file);
        pluginUpdateVo.setName(name);
        pluginUpdateVo.setType(type);

        //pluginService.checkFile(file);
        ValidatorUtils.validateEntity(pluginUpdateVo);
        if (pluginService.update(pluginUpdateVo)) {
            return ReturnT.ok();
        } else {
            return ReturnT.error();
        }
    }

    @GetMapping("query")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uuid", value = "UUID", dataType = "string", required = true)})
    @ApiOperation(value = "查询解析器")
    public ReturnT query(String uuid) {
        return ReturnT.ok();
    }

    @GetMapping("list")
    @ApiOperation(value = "查询解析器列表")
    public ReturnT list(PluginQueryVo queryVo) {
        return ReturnT.ok().put(pluginService.list(queryVo));
    }

    @PostMapping("delete")
    @ApiOperation(value = "删除解析器列表")
    public ReturnT delete(@RequestBody PluginDeleteVo deleteVo) {
        if (null == deleteVo) {
            throw new DataxException(ReturnCode.INVALID_PARAMETER, "参数错误,uuids不能为空");
        }
        return ReturnT.ok().put(pluginService.delete(deleteVo.getUuids()));
    }

    @GetMapping("download")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uuid", value = "UUID", dataType = "string", required = true)})
    @ApiOperation(value = "下载解析器")
    public void download(String uuid, HttpServletResponse response) throws IOException {
        PluginVo vo = pluginService.query(uuid);
        if (null == vo) {
            throw new DataxException(ReturnCode.INVALID_PARAMETER, "解析器不存在");
        }

        //获取解析器存储地址路径
        String filePath = pluginService.getFilePath(vo.getType());
        //解析器压缩文件路径
        String fileName = vo.getFileName();

        //设置文件名称
        response.setContentType("multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);

        String outputFilePath = filePath + fileName;

        String ext = "";
        int dot = fileName.lastIndexOf('.');
        if (dot > 0 && dot < fileName.length() - 1) {
            ext = fileName.substring(dot + 1).toLowerCase();
        }
        //拟压缩文件
        String inputFilePath = filePath + fileName.replace("." + ext, "");

        File file = new File(inputFilePath);
        if (!file.exists()) {
            throw new DataxException(ReturnCode.FILE_OPERATION_ERROR, "文件不存在");
        }

        ZipUtils.packet(Paths.get(inputFilePath), Paths.get(outputFilePath));

        // 发送给客户端的数据
        OutputStream outputStream = response.getOutputStream();
        byte[] buff = new byte[1024];
        BufferedInputStream bis = null;
        // 读取filename
        File outputFile = new File(outputFilePath);
        bis = new BufferedInputStream(new FileInputStream(outputFile));
        int i = bis.read(buff);
        while (i != -1) {
            outputStream.write(buff, 0, buff.length);
            outputStream.flush();
            i = bis.read(buff);
        }
        bis.close();
        FileUtils.deleteFile(outputFile);
    }


    @GetMapping("asyncById")
    @ApiOperation(value = "同步解析器到执行器")
    public ReturnT async(int id) {
        StringBuffer log = new StringBuffer();
        XxlJobGroup xxlJobGroup = xxlJobGroupDao.load(id);
        String addressList = xxlJobGroup.getAddressList();
        if (StringUtils.isEmpty(addressList)) {
            log.append("地址为空，无法同步");
            log.append("\n");
            return ReturnT.ok().put(log);
        }
        String[] urls = addressList.split(";");
        RestTemplate restTemplate = new RestTemplate();
        for (String url : urls) {
            if (url.endsWith("/")){
                url = url + "async";
            }else {
                url = url + "/async";
            }
            try {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                HashMap<String, String> map = new HashMap<>();
                HttpEntity< HashMap<String, String>> request =
                        new HttpEntity<>(map, headers);
                String result= restTemplate.postForObject(url, request, String.class);

                JSONObject jsonObject=JSON.parseObject(result);
                if (jsonObject.containsKey("code")&&jsonObject.getInteger("code").equals(ReturnCode.SUCCESS.getCode())){

                }else{
                    logger.error(jsonObject.toJSONString());
                    log.append("地址" + url + "同步失败，失败原因：" + jsonObject.getString("msg"));
                    log.append("\n");
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.append("地址" + url + "同步失败，失败原因：" + e.getMessage());
                log.append("\n");
            }
        }
        return ReturnT.ok().put(log);
    }

}
